#include "stdafx.h"
#include "render/Application_base.h"
#include "render/Surface.h"
#include "render/render.h"
#include "SDL_ttf.h"

namespace App
{

MouseState g_mouseState;

const MouseState& GetMouseState()
{
	return g_mouseState;
}

int SDLKeyCode(KeyCode keyCode)
{
	static int keys[] = 
	{
		SDLK_RCTRL,
		SDLK_LCTRL,
		SDLK_UP,
		SDLK_DOWN,
		SDLK_RIGHT,
		SDLK_LEFT,
		SDLK_w,
		SDLK_a,
		SDLK_s,
		SDLK_d,
		SDLK_RALT,
		SDLK_LALT,
	};

	return keys[keyCode];
}

bool KeyDown(KeyCode keyCode)
{
	U8* keyState = SDL_GetKeyState(NULL);
	return keyState[SDLKeyCode(keyCode)] != 0;
}

struct Event
{
	SDL_Event* pEvent;
};

EventType GetType(Event* pEvent)
{
	switch(pEvent->pEvent->type) 
	{
		case SDL_KEYDOWN: return EventType::EVENT_KEY_DOWN;
	}

	return EventType::EVENT_UNKNOWN;
}

KeyDownEvent GetKeyDownEvent(Event* pEvent)
{
	KeyDownEvent event;
	event.unicode = pEvent->pEvent->key.keysym.unicode;
	return event;
}

//////////////////////////////////////////////////////////////

struct LibData
{
	LibData() : pSurface(0) {}

	SDL_Surface* pSurface;
};

Application::Application() : m_pLibData(new LibData)
{
	m_running = true;
	m_videoWidth = 640;
	m_videoHeight = 480;
	m_appName = "App";
	m_pEventHandler = 0;
}

int Application::OnExecute() 
{
	if(OnInit_() == false) 
	{
		return -1;
	}

	SDL_Event sdlEvent;

	while(m_running) 
	{
		Uint8 ms = SDL_GetMouseState(&g_mouseState.x, &g_mouseState.y);
		g_mouseState.left = (ms & SDL_BUTTON(1)) != 0;
		g_mouseState.right = (ms & SDL_BUTTON(3)) != 0;

		while(SDL_PollEvent(&sdlEvent)) 
		{
			if (sdlEvent.type == SDL_QUIT)
				OnExit();

			if(sdlEvent.type == SDL_VIDEORESIZE)
			{
				m_videoWidth = sdlEvent.resize.w;
				m_videoHeight = sdlEvent.resize.h;
				SDL_SetVideoMode(m_videoWidth, m_videoHeight, 32, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE);
			}

			Event event;
			event.pEvent = &sdlEvent;
		
			if (m_pEventHandler)
				m_pEventHandler->OnEvent(&event);
		}

		OnUpdate_();
		OnRender_();
	}

	OnCleanup_();

	return 0;
}

void Application::SetVideoMode(int width, int height)
{
	m_videoWidth = width;
	m_videoHeight = height;
}

void Application::GetVideoMode(int& width, int& height)
{
	width = m_videoWidth;
	height = m_videoHeight;
}

void Application::SetAppName(const char* name)
{
	m_appName = name;
}

bool Application::OnInit_() 
{
	_putenv("SDL_VIDEO_WINDOW_POS");
	_putenv("SDL_VIDEO_CENTERED=1");

	if(SDL_Init(SDL_INIT_EVERYTHING) < 0) 
	{
		return false;
	}

	SDL_EnableUNICODE(1);

	if (TTF_Init() < 0)
	{
		return false;
	}

	if((m_pLibData->pSurface = SDL_SetVideoMode(m_videoWidth, m_videoHeight, 32, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE)) == NULL) 
	{
		return false;
	}

	SDL_WM_SetCaption(m_appName.c_str(), m_appName.c_str());

	if (OnInit() == false)
	{
		return false;
	}

	m_frameCount = 0;

	return true;
}

void Application::OnExit() 
{
    m_running = false;
}

void Application::OnUpdate_() 
{
	OnUpdate();
}

void Application::OnRender_() 
{
	OnRender();

	static U32 ticks = 0;
	static U32 oldTicks = 0;
	static float total = 0.f;
	float target = 1000.f / 60.f;
	
	oldTicks = ticks;
	ticks = SDL_GetTicks();
	m_frameTime = ticks - oldTicks;

	if (m_frameTime > target * 2) 
		m_frameTime = (int) target * 2;

	m_frameCount++;

	total += m_frameTime - target;

	if (total < target)
		Sleep((int)(target - total));

	SDL_Surface* pSurface = SDL_GetVideoSurface();
	SDL_Flip(pSurface);
}

U32 Application::GetFrameTime() const
{
	return m_frameTime;
}

U32 Application::GetFrameCount() const
{
	return m_frameCount;
}

void Application::OnCleanup_() 
{
	OnCleanup();

	TTF_Quit();

	SDL_Quit();
}

Render::SurfacePtr Application::MainView()
{
	return (Render::SurfacePtr) m_pLibData->pSurface;
}

}